package com.skyline.courier.net.provider.netty;

import io.netty.channel.Channel;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.socket.SocketChannel;

import java.io.IOException;
import java.net.SocketAddress;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.skyline.courier.net.Handler;
import com.skyline.courier.net.TransferBean;

public class NettyServerInitializer extends NettyEndPointInitializer {
	private static final Logger LOGGER = LoggerFactory.getLogger(NettyServerInitializer.class);
	protected Handler handler;
	
	public void setHandler(Handler handler) {
		this.handler = handler;
	}

	@Override
	protected void initChannel(SocketChannel ch) throws Exception {
		super.initChannel(ch);
		
		ChannelPipeline pipeline = ch.pipeline();
		
		if(handler != null) {
			pipeline.addLast("handler", new ChannelInboundHandlerAdapter() {
				@Override
				public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
					Object target = getTargetObject(msg);
					long seq = getSeq(msg);
					
					SocketAddress address = ctx.channel().remoteAddress();
					
					LOGGER.info("从[" + address + "]收到消息[" + target + "]");
					NettyServerInitializer.this.statistic.receivedMsg(address, System.currentTimeMillis());

					Throwable cause = null;
					Object result = null;
					try {
						result = handler.process(target);
					} catch(Throwable e) {
						cause = e;
					}
					ctx.writeAndFlush(createTransferBean(seq, result, cause));

					LOGGER.info("向[" + address + "]发送消息[" + (cause == null ? result : cause) + "]");
					NettyServerInitializer.this.statistic.sentMsg(address, System.currentTimeMillis());
				}
				
				@Override
				public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
					if (cause instanceof IOException) {
						Channel channel = ctx.channel();
						
						NettyServerInitializer.LOGGER.info("链接发生异常，channel[" + channel + "]", cause);
						
						ctx.close();
						
					} else {
						super.exceptionCaught(ctx, cause);
					}
				}
				
			});
		}
	}
	
	private Object getTargetObject(Object receiveObject) {
		if(receiveObject instanceof TransferBean) {
			TransferBean transferBean = (TransferBean) receiveObject;
			return transferBean.getTarget();
		} else {
			return receiveObject;
		}
	}
	
	private long getSeq(Object receiveObject) {
		if(receiveObject instanceof TransferBean) {
			TransferBean transferBean = (TransferBean) receiveObject;
			return transferBean.getSeq();
		} else {
			return -1;
		}
	}
	
	private TransferBean createTransferBean(long requestSeq, Object result, Throwable cause) {
		TransferBean transferBean = new TransferBean();
		transferBean.setSeq(requestSeq);
		transferBean.setTarget(cause == null ? result : cause);
		return transferBean;
	}

}
